﻿using Spider.Framework.UtilityCommon;
using System;
using System.Collections.Generic;
using System.Text.RegularExpressions;
using Spider.Framework.UtilityCommon.Extensions;
using MyCrawler.Entity;
using MyCrawler.Dals;
using MyCrawler.Utilyties;

namespace MyCrawler.Controls
{
    public class GenKForumCtr : ForumsCtr
    {
        public GenKForumCtr()
        {
            _source = "forum.genk.vn";
            _domain = "http://forum.genk.vn/";
            _linkInit = "http://forum.genk.vn/";
            _blockId = DateTime.Now.ToString("yyyyMMddhhmmss");
            _pageLimit = -1;
        }

        /// <summary>
        /// Contructor thứ 2
        /// </summary>
        /// <param name="source">nguồn</param>
        /// <param name="linkInit">link khởi tạo</param>
        /// <param name="domain">domain gốc - có thể trùng với link khởi tạo</param>
        /// <param name="blockId">mỗi lần khởi tạo sẽ có 1 block id, chứa list các thread</param>
        public GenKForumCtr(string source, string linkInit, string domain, string blockId)
        {
            _source = source;
            _linkInit = linkInit;
            _domain = domain; // dùng cho các trang sub trở đi, vì sẽ nối trang với domain
            _blockId = blockId;

            _pageLimit = -1;
        }

        public override List<string> GetCatalogByLink()
        {
            try
            {
                string html = GetContentWithStream(_linkInit, 333); // delay 333 mili giây trước khi request
                List<string> ls_L1 = UtilityCtr.GetListItem(html, @"<li[\s]+class='node[\s]+forum[\s]+level_2[\s]+node_[\d]+'>.*?<\/li>");

                List<string> lsLinkStored = new List<string>();
                for (int i = 0; i < ls_L1.Count; i++)
                {
                    string ln = _linkInit + UtilityCtr.GetItemFirst(ls_L1[i], @"href='.*?'").Replace("href='", "").Replace("'", "");
                    lsLinkStored.Add(ln);
                }
                return lsLinkStored;
            }
            catch { }

            return null;
        }

        public override void GetListTopic_InCatagory(string lnk)
        {
            try
            {
                TraceLog_Status(_source, _blockId, " + " + lnk);

                string s = GetContentWithStream(lnk, 333); // delay 333 mili giây trước khi request

                if (s.IsStringNullOrEmpty())
                {
                    TraceLog_Status(_source, _blockId, " --- Data null Or empty. WebClient request time out. Kiểm tra Website có bị chết hay không hay kiểm tra kết nối internet của bạn! "); // ghi log để test
                    return;
                }

                // lấy các chủ đề ngày trang đầu
                GetTopicsInPage(s, 1);

                #region [làm việc từ trang thứ 2 trở đi]
                try
                {
                    string pager = s.GetElement(@"(Trang[\s]+[\d]+\/[\d]+)|(Page[\s]+[\d]+\/[\d]+)", false, PatternType.Regex);

                    int totalPage = Convert.ToInt32(Regex.Replace(pager, @"(Trang[\s]+[\d]+\/)|(Page[\s]+[\d]+\/)", "").Trim());
                    _pageLimit = -1; // khởi tạo trang giới hạn
                    for (int i = 2; i <= totalPage; i++) // duyêt từ trang số 2 trở đi
                    {
                        if (_pageLimit != -1 && i > _pageLimit) // đã tìm thấy trang giới hạn, trang này có ngày cập nhật nhỏ hơn ngày giới hạn
                        {
                            break;
                        }

                        string linkPager = lnk + "page-" + i;
                        s = GetContentWithStream(linkPager, 333); // delay 333 mili giây trước khi request

                        GetTopicsInPage(s, i); // lấy các chủ đề của trang 1
                    }
                }
                catch { }
                #endregion
            }
            catch { }
        }

        /// <summary>
        /// Lấy các chủ đề của trang đầu tiên, trang này thường chứa các topic được khóa hay sticky
        /// </summary>
        /// <returns></returns>
        private void GetTopicsInPage(string contentHtml, int pageIndex)
        {
            try
            {
                var lisTopic = UtilityCtr.GetListItem(contentHtml, @"<li[\s]+id='thread-[\d]+'.*?<\/dl><\/div><\/li>");
                if (lisTopic == null || lisTopic.Count == 0)
                {
                    TraceLog_Status(_source, _blockId, " --- --- --- không tìm thấy Topic, kiểm tra Catagorie này có thay đổi source code!");
                    return;
                }

                if (lisTopic.Count > 0)
                {
                    for (int i = 0; i < lisTopic.Count; i++)
                    {
                        var arrdate = UtilityCtr.GetListItem(lisTopic[i], @"[\d]+\/[\d]+\/[\d]+ lúc [\d]+:[\d]+");

                        if (arrdate == null || arrdate.Count == 0)
                        {
                            TraceLog_Status(_source, _blockId, " --- Ngày 'last reply' không tồn tại, có thể chủ đề đã bị xóa, đã di chuyển, hay website nguồn có sự thay đổi souce code!");
                            continue;
                        }

                        //17/04/2014 00:00
                        string date = arrdate[arrdate.Count - 1].Replace(" lúc ", " ");

                        string[] sArrDate = date.Split(' ');
                        if (sArrDate.Length == 2)
                        {
                            string[] arrDay = sArrDate[0].Split('/');

                            if (arrDay.Length == 3)
                            {
                                date = arrDay[2] + "-" + arrDay[1] + "-" + arrDay[0] + " " + sArrDate[1];
                            }
                        }
                        DateTime dtLastDate;
                        try
                        {
                            dtLastDate = Convert.ToDateTime(date);

                            // kiểm tra ngày này có nhỏ hơn ngày giới hạn lấy hay không?
                            if (dtLastDate >= _dtLimit)// trong thời gian 30 ngày mà không có ai trả lời, không lấy dữ liệu mới về nữa
                            {
                                #region thực hiện lấy data
                                string lnk = lisTopic[i].GetElement(@"href='threads\/[\d]+\/'", false, PatternType.Regex).Replace("href='", "").Replace("'", "");
                                lnk = Regex.Replace(lnk, @"<a.*?>", "");

                                string subj = lisTopic[i].GetElement(@"<a href='threads\/[\d]+\/'.*?>.*?<\/a>", false, PatternType.Regex);
                                subj = Regex.Replace(subj, @"<.*?>", "");

                                int id;
                                try
                                {
                                    id = Convert.ToInt32(lnk.Replace("threads/", "").Replace("/", "")); // mai test ở đây
                                }
                                catch
                                {
                                    id = 0;
                                }

                                lnk = _linkInit + lnk;
                                #endregion

                                GetContent(lnk, subj, id, dtLastDate);
                            }
                            else
                            {
                                if (pageIndex > 1)
                                {
                                    _pageLimit = pageIndex; // chủ đề này có thời gian post cũ hơn ngày giới hạn, thoát luôn và không quan tâm chủ đề cũ hơn nữa
                                    break;
                                }
                            }
                        }
                        catch
                        { }
                    }
                }
            }
            catch (Exception ex)
            {
                TraceLog_Status(_source, _blockId, " --- --- Error: " + ex.Message);
            }
        }

        public void GetContent(string lnk, string subj, long idTopic, DateTime lastModify)
        {
            try
            {
                TraceLog_Status(_source, _blockId, " --- " + lnk);

                string html = GetContentWithStream(lnk, 500); // delay 500 mili giây trước khi request
                if (html.IsStringNullOrEmpty())
                {
                    TraceLog_Status(_source, _blockId, " --- --- Data null Or empty. WebClient request time out. Kiểm tra Website có bị chết hay không hay kiểm tra kết nối internet của bạn! "); // ghi log để test
                    return;
                }

                #region lấy tên danh mục
                var catLis = html.GetElements(@"<span itemprop='title'>.*?<\/span>", false, PatternType.Regex);
                string catName = "";
                if (catLis != null && catLis.Count > 0)
                {
                    catName = Regex.Replace(catLis[catLis.Count - 1], @"<.*?>", "").Trim();
                }
                #endregion

                // xóa đi trích dẫn (nếu tồn tại)
                html = Regex.Replace(html, @"(<div class='bbCodeBlock bbCodeQuote' data-author=').*?(<\/aside><\/div>)", "");

                // lấy danh sách bài viết
                var lisPost = html.GetElements(@"<article>.*?<\/article>", false, PatternType.Regex);
                if (lisPost == null || lisPost.Count == 0)
                {
                    TraceLog_Status(_source, _blockId, " --- --- --- không tìm thấy bài viết & bình luận, trang này có thay đổi source code!"); // ghi log để test
                    return;
                }

                //[lấy nội dung bài viết - mẩu tin đầu của trang đầu
                string cont = Regex.Replace(lisPost[0], @"<.*?>", " ");
                cont = Regex.Replace(cont, @"[\s]+", " ").Trim();

                #region [lấy bình luận trang đầu]
                List<string> lsCmt = new List<string>();
                for (int i = 1; i < lisPost.Count; i++)
                {
                    // xóa đi trích dẫn
                    string cmt = Regex.Replace(lisPost[i], @"<.*?>", " ");
                    cmt = Regex.Replace(cmt, @"[\s]+", " ").Trim();

                    lsCmt.Add(cmt);
                }
                #endregion

                #region lấy bình luận từ trang 2 trở đi
                try
                {
                    string pager = html.GetElement(@"Trang[\s][\d]+\/[\d]+", false, PatternType.Regex);
                    int totalPage = Convert.ToInt32(Regex.Replace(pager, @"[\s\S]+.*?\/", "").Trim());
                    for (int i = 2; i <= totalPage; i++) // duyêt từ trang số 2 trở đi
                    {
                        string lnkSub = lnk + "page-" + i.ToString();
                        string htmlSub = GetContentWithStream(lnkSub, 500); // delay 500 mili giây trước khi request

                        // xóa đi trích dẫn (nếu tồn tại)
                        htmlSub = Regex.Replace(htmlSub, @"(<div class='bbCodeBlock bbCodeQuote' data-author=').*?(<\/aside><\/div>)", "");

                        /// lấy danh sách
                        var lisPostSub = UtilityCtr.GetListItem(htmlSub, @"<article>.*?<\/article>");
                        for (int j = 0; j < lisPostSub.Count; j++)
                        {
                            #region lấy các bình luận
                            // xóa đi trích dẫn
                            string cmtsub = Regex.Replace(lisPostSub[j], @"<.*?>", " ");
                            cmtsub = Regex.Replace(cmtsub, @"[\s]+", " ").Trim();

                            lsCmt.Add(cmtsub);
                            #endregion
                        }

                    }
                }
                catch { }
                #endregion

                #region [save]

                ContentEntity entity = new ContentEntity();

                entity.Category = catName;
                entity.Comments = lsCmt;
                entity.Content = cont;
                entity.Id = idTopic;
                entity.LastModify = lastModify;
                entity.Link = lnk;
                entity.Source = _source;
                entity.Summury = "";
                entity.Title = subj;

                // ghi log để review
                TraceLog_Status(_source, _blockId, " --- --- Comments: " + lsCmt.Count.ToString() + " -- Last modify: " + lastModify.ToString("yyyy-MM-dd hh:mm:ss tt"));
                // lưu vào file json
                string file = LogFileJson(entity);
                // ghi log để review
                TraceLog_Status(_source, _blockId, " --- --- File json: " + file);

                // tăng số topic lên 1 để thực hiện việc thống kê
                _totalTopic = _totalTopic + 1;
                UtilityCtr.TraceSettingTime(_source, _timeStart, _totalTopic, _dtLimit.ToString("yyyy-MM-dd hh:mm:ss tt"));

                #endregion
            }
            catch (Exception ex)
            {
                TraceLog_Status(_source, _blockId, " --- --- Error: " + ex.Message); // ghi log để test
            }
        }
    }
}
